/* http://www.libpng.org/pub/png/book/chapter13.html */

#include "png.h"

static png_structp png_ptr;
static png_infop info_ptr;

static unsigned int width;
static unsigned int height;
static int bit_depth;
static int color_type;

void readpng_version_info();
int readpng_init(FILE*, long*, long*);
int readpng_get_bgcolor(unsigned char *red, unsigned char *green, unsigned char *blue);


void readpng_version_info() {
    fprintf(stderr, "  compiled with libpng %s; using libpng %s\n", PNG_LIBPNG_VER_STRING, png_libpng_ver);
    //fprintf(stderr, "  compiled with zlip %s; using zlib %s\n", ZLIB_VERSION, zlib_version);
}

int readpng_init(FILE *infile, long *pWidth, long *pHeight) {
    /* 1 housekeeping */
    unsigned char sig[8];

    fread(sig, 1, 8, infile);
    if (!png_check_sig(sig, 8))
        return 1; // bad signature

    png_ptr = png_create_read_struct(
        PNG_LIBPNG_VER_STRING, 
        NULL, 
        NULL, 
        NULL
    );
    if (!png_ptr)
        return 4; // out of memory

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return 4; // out of memory
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return 2;
    }

    /* 2 actual png reading */
    png_init_io(png_ptr, infile);
    png_set_sig_bytes(png_ptr, 8);
    png_read_info(png_ptr, info_ptr);

    png_get_IHDR(
        png_ptr, info_ptr, 
        &width, &height, 
        &bit_depth, &color_type, 
        NULL, NULL, NULL
    );

    *pWidth = width;
    *pHeight = height;

    return 0;
}

int readpng_get_bgcolor(unsigned char *red, unsigned char *green, unsigned char *blue) {
    if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD))
        return 1;

    png_color_16p pbackground;
    png_get_bKGD(png_ptr, info_ptr, &pbackground);

    /* half bit_depth requires bitshifts */
    if (bit_depth == 16) {
        *red   = pbackground->red   >> 8;
        *green = pbackground->green >> 8;
        *blue  = pbackground->blue  >> 8;
    /* grayscale is treated specially */
    } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
        /* bit_depth of 1 gives us only 2 colors */
        if (bit_depth == 1)
            *red = *green = *blue = pbackground->gray ? 255 : 0;
        /* bit_depth of 2 gives us 3 as max value */
        else if (bit_depth == 2)
            *red = *green = *blue = (255/3) * pbackground->gray;
        /* bit_depth of 4 gives us 15 as max value */
        else
            *red = *green = *blue = (255/15) * pbackground->gray;
    } else {
        *red = pbackground->red;
        *green = pbackground->green;
        *blue = pbackground->blue;
    }

    return 0;
}
